// 模型管理器 - 专门处理3D模型加载和管理
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js'
import { ERROR_MESSAGES } from '../config/constants.js'

export class ModelManager {
  constructor() {
    this.loadedModels = new Map()
    this.gltfLoader = new GLTFLoader()
    this.objLoader = new OBJLoader()
    this.fbxLoader = new FBXLoader()
  }

  async loadModel(path) {
    if (this.loadedModels.has(path)) {
      return this.loadedModels.get(path).clone()
    }

    const extension = this.getFileExtension(path)
    
    return new Promise((resolve, reject) => {
      const onLoad = (object) => {
        this.prepareModel(object)
        this.loadedModels.set(path, object)
        resolve(object.clone())
      }

      const onError = (error) => {
        console.error(ERROR_MESSAGES.MODEL_LOAD_FAILED, error)
        reject(error)
      }

      switch (extension) {
        case 'gltf':
        case 'glb':
          this.gltfLoader.load(path, (gltf) => onLoad(gltf.scene), undefined, onError)
          break
        case 'obj':
          this.objLoader.load(path, onLoad, undefined, onError)
          break
        case 'fbx':
          this.fbxLoader.load(path, onLoad, undefined, onError)
          break
        default:
          reject(new Error(ERROR_MESSAGES.UNSUPPORTED_FORMAT))
      }
    })
  }

  prepareModel(object) {
    object.traverse((child) => {
      if (child.isMesh) {
        child.castShadow = true
        child.receiveShadow = true
        
        // 确保几何体有正确的法线
        if (!child.geometry.attributes.normal) {
          child.geometry.computeVertexNormals()
        }
      }
    })
  }

  createGeometry(type) {
    switch (type) {
      case 'BoxGeometry':
        return new THREE.BoxGeometry(2, 2, 2)
      case 'SphereGeometry':
        return new THREE.SphereGeometry(1.5, 32, 32)
      case 'CylinderGeometry':
        return new THREE.CylinderGeometry(1, 1, 2, 32)
      case 'TorusGeometry':
        return new THREE.TorusGeometry(1, 0.4, 16, 100)
      case 'ConeGeometry':
        return new THREE.ConeGeometry(1, 2, 32)
      default:
        return new THREE.BoxGeometry(2, 2, 2)
    }
  }

  getFileExtension(path) {
    return path.split('.').pop().toLowerCase()
  }

  dispose() {
    this.loadedModels.forEach(model => {
      model.traverse((child) => {
        if (child.isMesh) {
          child.geometry.dispose()
          if (child.material) {
            if (Array.isArray(child.material)) {
              child.material.forEach(material => material.dispose())
            } else {
              child.material.dispose()
            }
          }
        }
      })
    })
    this.loadedModels.clear()
  }
}